<?php

namespace App\Http\Controllers\AgentAdmin;

use App\Enums\AssetSourceType;
use App\Enums\AssetStatus;
use App\Enums\ProductStatus;
use App\Enums\ProductType;
use App\Enums\TokenLockType;
use App\Enums\TokenStatus;
use App\Exports\AirdropsExport;
use App\Http\Controllers\Controller;
use App\Jobs\DownloadsJob;
use App\Models\AgentUser;
use App\Models\Airdrop;
use App\Models\Asset;
use App\Models\BlindBoxItem;
use App\Models\BlindBoxRecord;
use App\Models\Download;
use App\Models\FrontendUser;
use App\Models\Product;
use App\Models\ProductToken;
use App\Services\WalletService;
use App\Utils\UploadHelper;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Vinlon\Laravel\LayAdmin\Exceptions\AdminException;

class AirdropController extends Controller
{
    /** @var WalletService */
    private $walletService;

    /**
     * Create the event listener.
     */
    public function __construct(WalletService $walletService)
    {
        $this->walletService = $walletService;
    }

    /**
     * 获取空投记录.
     *
     * @return mixed
     */
    public function index()
    {
        $user = auth()->user();

        $query = Airdrop::query()
            ->where('agent_id', $user->agent_id)
            ->where('type', request()->type)
            ->when(request()->keyword, function ($q) {
                return $q->where(function ($q1) {
                    $likeVal = '%' . request()->keyword . '%';

                    return $q1->where('nickname', 'like', $likeVal)->orWhere('mobile', 'like', $likeVal)->orWhere('goods_name', 'like', $likeVal);
                });
            })
            ->when(request()->start_date, function ($q) {
                $q->whereDate('created_at', '>=', request()->start_date);
            })
            ->when(request()->end_date, function ($q) {
                $q->whereDate('created_at', '<=', request()->end_date);
            })
            ->when(request()->status, function ($q) {
                if (3 == request()->status) {
                    request()->status = 0;
                }

                return $q->where('status', request()->status);
            })
            ->orderByDesc('id');

        return paginate_result($query);
    }

    /** 空投商品 */
    public function store(Request $request)
    {
        $data = $request->toArray();
        $agent = auth()->user();
        $error_flag = false;

        $error_msg = '';
        foreach ($data['mobile'] as $k => $v) {
            if (empty($v) || empty($data['goods_id'][$k]) || empty($data['number'][$k])) {
                $tmp['mobile'] = $v;
                $tmp['goods_id'] = $data['goods_id'][$k];
                $tmp['msg'] = '商品id、手机号、数量不能为空';

                continue;
            }

            if ($data['number'][$k] > 50) {
                $tmp['mobile'] = $v;
                $tmp['goods_id'] = $data['goods_id'][$k];
                $tmp['msg'] = '数量不能大于50';

                continue;
            }

            $user = FrontendUser::where('mobile', $v)->where('agent_id', $agent->agent_id)->first();

            if (empty($user)) {
                $tmp['mobile'] = $v;
                $tmp['goods_id'] = $data['goods_id'][$k];
                $tmp['msg'] = '找不到用户';
                $error_flag = true;
                $error_msg .= '手机号' . $tmp['mobile'] . ',找不到用户;';

                continue;
            }

            $goods = Product::where('id', $data['goods_id'][$k])->where('agent_id', $agent->agent_id)->first();

            if (empty($goods)) {
                $tmp['mobile'] = $v;
                $tmp['goods_id'] = $data['goods_id'][$k];

                $tmp['msg'] = '找不到商品';
                $error_flag = true;
                $error_msg .= '商品id' . $data['goods_id'][$k] . ',找不到对应商品;';

                continue;
            }
            $order_sn = date('YmdHis') . mt_rand(1000000, 9999999);

            $save_data = [
                'agent_id' => $agent->agent_id,
                'order_sn' => $order_sn,
                'mobile' => $v,
                'goods_id' => $data['goods_id'][$k],
                'number' => $data['number'][$k],
                'nickname' => $user->nickname,
                'goods_name' => $goods->name,
                'goods_img' => $goods->logo_url,
                'tokenIds' => '',
                'qianbao' => $user->wallet_address,
                'status' => 0,
                'created_at' => date('Y-m-d H:i:s'),
            ];
            Airdrop::create($save_data);
        }
        if ($error_flag) {
            return ['data' => 1, 'msg' => $error_msg];
        }

        return [];
    }

    /** 空投盲盒 */
    public function storeBlindBoxAirdrop()
    {
        $data = request()->all();

        DB::transaction(function () use ($data) {
            /** @var AgentUser $loginUser */
            $loginUser = auth()->user();
            $batchRecords = [];
            $errorMsg = '';
            foreach ($data['mobile'] as $k => $v) {
                if (empty($v) || empty($data['goods_id'][$k]) || empty($data['number'][$k])) {
                    $errorFlag = true;
                    $errorMsg .= '商品id、手机号、数量不能为空';

                    throw new AdminException($errorMsg);
                }

                if ($data['number'][$k] > 50) {
                    $errorMsg .= '数量不能大于50';

                    throw new AdminException($errorMsg);
                }

                $user = FrontendUser::query()->where('mobile', $v)->where('agent_id', $loginUser->agent_id)->first();

                if (empty($user)) {
                    $errorFlag = true;
                    $errorMsg .= '手机号' . $v . ',找不到用户;';

                    throw new AdminException($errorMsg);
                }

                /** @var Product $goods */
                $goods = Product::query()
                    ->where('type', ProductType::BLIND_BOX)
                    ->where('id', $data['goods_id'][$k])
                    ->where('agent_id', $loginUser->agent_id)->first();

                if (empty($goods)) {
                    $errorFlag = true;
                    $errorMsg .= '商品id' . $data['goods_id'][$k] . ',找不到对应商品;';

                    throw new AdminException($errorMsg);
                }
                if (ProductStatus::ON_SALE == $goods->status) {
                    $errorFlag = true;
                    $errorMsg .= '商品id' . $data['goods_id'][$k] . ',发行状态不支持空投;';

                    throw new AdminException($errorMsg);
                }
                if ($goods->left_count < $data['number'][$k]) {
                    $errorFlag = true;
                    $errorMsg .= '商品id' . $data['goods_id'][$k] . ',商品库存不足;';

                    throw new AdminException($errorMsg);
                }

                $order_sn = date('YmdHis') . mt_rand(1000000, 9999999);

                $save_data = [
                    'agent_id' => $user->agent_id,
                    'order_sn' => $order_sn,
                    'mobile' => $v,
                    'goods_id' => $data['goods_id'][$k],
                    'number' => $data['number'][$k],
                    'nickname' => $user->nickname,
                    'goods_name' => $goods->name,
                    'goods_img' => $goods->logo_url,
                    'tokenIds' => '',
                    'qianbao' => '',
                    'status' => 1,
                    'type' => ProductType::BLIND_BOX,
                    'created_at' => date('Y-m-d H:i:s'),
                ];
                Airdrop::create($save_data);

                // 库存更新
                $goods->decrement('left_count', $data['number'][$k]);
                $goods->increment('sales_count', $data['number'][$k]);

                /** @var BlindBoxItem[] $blindBoxItems */
                $blindBoxItems = BlindBoxItem::query()
                    ->with(['product_token'])
                    ->where('blind_box_id', $goods->id)->where('status', TokenStatus::INIT)
                    ->limit($data['number'][$k])
                    ->orderBy('sequence')->get();

                foreach ($blindBoxItems as $blindBoxItem) {
                    $batchRecords[] = [
                        'user_id' => $user->id,
                        'order_id' => 0,
                        'blind_box_id' => $goods->id,
                        'asset_product_id' => $blindBoxItem->product_id,
                        'asset_token_id' => $blindBoxItem->product_token->token_id,
                        'created_at' => now(),
                        'updated_at' => now(),
                    ];
                }

                BlindBoxItem::query()->whereIn('id', Arr::pluck($blindBoxItems, 'id'))->update([
                    'status' => TokenStatus::SOLD(),
                ]);
            }
            BlindBoxRecord::query()->insert($batchRecords);
        });
    }

    /** 空投文件上传 */
    public function import(Request $request)
    {
        $isFile = $request->hasFile('file');
        if (!$isFile) {
            throw new \Exception('请上传文件');
        }
        $data = UploadHelper::readExcel($request->file('file'));
        unset($data[0]);

        return $data;
    }

    public function reissue($id)
    {
        $airdrop = $this->findAirdropOrFail($id);

        $goods = Product::where('id', $airdrop->goods_id)->where('agent_id', $airdrop->agent_id)->first();

        if (empty($goods)) {
            throw new AdminException('空投未找到');
        }

        $contractAddress = $goods->contract_address;
        $quantity = 1;
        $tokens = ProductToken::query()->where('product_id', $goods->id)
            ->where('status', TokenStatus::INIT)
            ->limit($quantity)->get();

        $productTokenIds = Arr::pluck($tokens, 'id');
        $tokenIds = Arr::pluck($tokens, 'token_id');

        if (count($tokenIds) < $quantity) {
            $airdrop->status = 2;
            $airdrop->error_msg = '库存不足';
            $airdrop->save();

            throw new AdminException('库存不足');
        }

        $airdrop->tokenIds = json_encode($tokenIds);

        // 锁定
        ProductToken::query()->whereIn('id', $productTokenIds)->update([
            'lock_type' => TokenLockType::AIRDROP,
            'lock_refer_id' => $airdrop->id,
            'status' => TokenStatus::LOCKED,
        ]);

        $user = FrontendUser::where('mobile', $airdrop->mobile)->where('agent_id', $airdrop->agent_id)->first();

        try {
            $fromMobile = ''; // 默认使用商品发布时的收款方为付款方
            if ($goods->resale_user) {
                $fromMobile = $goods->resale_user->mobile;
            }
            $transResult = $this->walletService->transfer(
                $fromMobile,
                $contractAddress,
                $tokenIds,
                $user->wallet_address
            );
            // 更新token状态
            foreach ($tokens as $token) {
                $transHash = Arr::get($transResult, $token->token_id, 'trans_hash_not_return');
                $token->status = TokenStatus::SOLD;
                $token->save();

                // 保存资产信息
                $asset = new Asset();
                $asset->user_id = $user->id;
                $asset->source_type = AssetSourceType::AIRDROP;
                $asset->source_id = $airdrop->id;
                $asset->contract_address = $goods->contract_address;
                $asset->token_id = $token->token_id;
                $asset->trans_hash = $transHash;
                $asset->asset_status = AssetStatus::HOLD;
                $asset->save();
            }
            $airdrop->status = 1;
            $airdrop->save();
        } catch (\Exception $e) {
            ProductToken::query()->whereIn('id', $productTokenIds)->update([
                'status' => TokenStatus::FAILED,
            ]);

            $airdrop->status = 2;
            $airdrop->error_msg = $e->getMessage();
            $airdrop->save();

            throw new AdminException($e->getMessage());
        }
    }

    /** 空投记录导出 */
    public function export()
    {
        $user = auth()->user();

        $file = '空投' . date('YmdHis') . uniqid() . '.xls';

        $download = Download::create([
            'agent_id' => $user->agent_id,
            'user_id' => $user->id,
            'name' => $file,
            'url' => 'storage/' . $file,
            'status' => 0,
            'model' => AirdropsExport::class,
            'request' => json_encode(request()->all()),
        ]);

        dispatch(new DownloadsJob($download));
    }

    private function findAirdropOrFail($id)
    {
        /** @var AgentUser $user */
        $user = auth()->user();
        $airdrop = Airdrop::where('agent_id', $user->agent_id)
            ->find($id);
        if (!$airdrop) {
            throw new AdminException('空投未找到');
        }

        return $airdrop;
    }
}
